package com.slowfly.rule.engine.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.slowfly.rule.engine.bean.CacheBean;
import com.slowfly.rule.engine.component.RedisComponent;
import com.slowfly.rule.engine.constants.IRiskConstants;
import com.slowfly.rule.engine.entity.Scene;
import com.slowfly.rule.engine.entity.Strategy;
import com.slowfly.rule.engine.enums.OptEnum;
import com.slowfly.rule.engine.mapper.SceneMapper;
import com.slowfly.rule.engine.mapper.StrategyMapper;
import com.slowfly.rule.engine.param.SceneParam;
import com.slowfly.rule.engine.result.PageResult;
import com.slowfly.rule.engine.result.SceneResult;
import com.slowfly.rule.engine.service.ISceneService;
import com.google.common.collect.Maps;
import com.slowfly.rule.engine.util.PageResultConvert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author shalongfei
 * @since 2024-02-22
 */
@Slf4j
@Service
public class SceneServiceImpl extends ServiceImpl<SceneMapper, Scene> implements ISceneService {

    @Autowired
    private StrategyMapper strategyMapper;
    @Autowired
    private RedisComponent redisComponent;

    private Map<Integer, Scene> sceneCache;

    public void setCache() {
        Map<Integer, Scene> sceneCache = Maps.newConcurrentMap();
        for (Scene scene : list()) {
            sceneCache.put(scene.getId(), scene);
        }
        this.sceneCache = sceneCache;
    }

    public void editCache(int type, int id) {
        if (type == OptEnum.ADD.getCode() || type == OptEnum.EDIT.getCode()) {
            sceneCache.put(id, getById(id));
        } else if (type == OptEnum.DELETE.getCode()) {
            sceneCache.remove(id);
        }
    }

    public Scene get(Integer id) {
        return sceneCache.get(id);
    }

    public Scene getByCode(String code) {
        for (Scene scene : sceneCache.values()) {
            if (Objects.equals(code, scene.getCode())) {
                return scene;
            }
        }
        return null;
    }

    public List<SceneResult> listScene() {
        return BeanUtil.copyToList(list(), SceneResult.class);
    }

    public PageResult<SceneResult> pageScene(SceneParam param) {
        LambdaQueryWrapper<Scene> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(param.getName()), Scene::getName, param.getName());
        queryWrapper.like((StringUtils.isNotBlank(param.getCode())), Scene::getCode, param.getCode());
        queryWrapper.orderByDesc(Scene::getUpdateTime);
        Page<Scene> page = page(new Page<>(param.getPageNo(), param.getPageSize()), queryWrapper);
        return PageResultConvert.convert(page, SceneResult.class);
    }

    public boolean addScene(SceneParam param) {
        Scene scene = new Scene();
        BeanUtils.copyProperties(param, scene);
        boolean saved = save(scene);
        redisComponent.publish(IRiskConstants.SCENE_CHANEL, new CacheBean(OptEnum.ADD.getCode(), scene.getId()));
        return saved;
    }

    public boolean editScene(SceneParam param) {
        Scene scene = new Scene();
        BeanUtils.copyProperties(param, scene);
        boolean updated = updateById(scene);
        redisComponent.publish(IRiskConstants.SCENE_CHANEL, new CacheBean(OptEnum.EDIT.getCode(), param.getId()));
        return updated;
    }

    public boolean deleteScene(SceneParam param) {
        LambdaQueryWrapper<Strategy> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strategy::getSceneId, param.getId());
        long count = strategyMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("请先删除该场景下的策略!");
        }
        boolean removed = removeById(param.getId());
        redisComponent.publish(IRiskConstants.SCENE_CHANEL, new CacheBean(OptEnum.DELETE.getCode(), param.getId()));
        return removed;
    }

}
